package stmlib;

/**
 * Tutorial for StmLib, the STM Library.  Everything you need to know.
 * Hint: the tutorial is embedded in the source!
 * @author Seun Osewa. Copyright (c) 2010.  All rights reserved.
 */
public class Tutorial {
    static int globalInt;
    static Var<Integer> globalVar =  new Var<Integer>(0);

    public void println(String output) {
        System.out.println(output);
    }

    /** the tutorial is delivered in the text of this function.  Read the source! */
    public void main(String[] argv) {
        // STMlib is a tool for writing multithreaded programs without any hassle.  It provides
        // a collection of fast, composable, thread-safe, transaction-aware data structures.
        // Data stored in STMlib objects can be manipulated by more than one thread without
        // incorrect results caused by race conditions, deadlocks due to incorrect locking, etc.
        // STMlib transactions work just like database transactions, but are 1000 times as fast.

        // First step:        
        //   import stmlib.*;
        // - the package name is not fully qualified, but it's short and easy to remember.
        // - the classes in the library are reasonably unique; name clashes aren't likely.

        // A 'List' is a transactional object that wraps a java.util.ArrayList and fully
        // implements the java.util.List interface.  But it works with STMlib transactions:
        final StmList<Integer> l = new StmList<Integer>();

        // StmLists can be created anywhere, but should be used only within a TransactionT:
        boolean success = new TransactionT<Boolean>(){public Boolean atomic(){
            for (int i = 0; i < 10; i++) { l.add(1); } //add the numbers 1 to 10 to the StmList.
            return true;
        }}.execute();
        // Note: the StmList can be safely shared by several threads without any explicit locking.

        // A TransactionT.V is shortcut for a transaction that doesn't return a value:
        new TransactionT.V(){public void atomicV(){
            for (int i = 0; i < 10; i++) { l.add(1); } //same as above, but more concise.
        }}.execute();

        // Transactions SHOULD NOT have side-effects:
        new TransactionT.V(){public void atomicV(){
            // They MUST NOT do any IO e.g. file operations, socket operations, console IO, etc
            System.out.println(l); //wrong!

            // They MAY use Stm.onCommit() to schedule IO events to occur after commit()
            Stm.onCommit(new Runnable() { public void run() {
                System.out.println(l); //correct!
            }});

            // -- OR --
            Stm.println(l); //correct: prints if the transaction successfully commits.

            // They MUST NOT mutate shared nontransactional variables / fields
            Tutorial.globalInt = 5; //wrong!

            // You MAY use a Var in place of a shared variable/field:
            // ### static Var<Integer> globalVar =  new Var<Integer>(0);
            globalVar.set(5); // correct.  outside the transaction, do: globalVar.peek();
        }}.execute();
        // - the STMlib runtime may need to retry the transaction by rerunning this method.
        // - the STMlib may need to rollback this transaction. Side-effects/IO can't be rolled back.

        // If an Exception is thrown in a transaction, the entire transaction is rolled back.
        // If the transaction was properly written, a rollback is as if it was never executed!
        new TransactionT.V(){public void atomicV() throws Exception{
            l.clear(); l.add(1); l.add(2); // l contains [1, 2];
            throw new Exception("oops");
        }}.execute(); // l is unchanged at this point.

        // All in-transaction Exceptions are wrapped in a RuntimeException for usability.
        // You need to unwrap them to handle the exceptions externally, if you really need to.
        try {
            new TransactionT.V(){public void atomicV() throws Exception{
                throw new NoSuchMethodException("Catch This");
            }}.execute(); // l is unchanged at this point.
        } catch (Exceptions.Wrap wrapper) {
            // wrapper.exception ### do something with it: rethrow, etc.
        }
    }
}